/****************************************************************************
**
** Copyright (C) 2010 Tieto Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Tieto Corporation (info.ostrava@tieto.com)
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Tieto.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Tieto gives you certain additional
** rights.  These rights are described in the Tieto Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you have questions regarding the use of this file, please contact
** Tieto at info.ostrava@tieto.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/QStringList>
#include <QtGui/QImage>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtXml/QXmlInputSource>
#include <QtXml/QXmlParseException>
#include <QDebug>

#include "convolutionfactory.h"
#include "convolutiontask.h"
#include "convolutionmask.h"

#define NAME "name"
#define MASK "mask"
#define ROWS "rows"
#define COLS "cols"
#define DATA "data"
#define ROW "row"
#define COL "col"

ConvolutionFactory::ConvolutionFactory(ConvolutionModel &model, QObject *parent)
    : QObject(parent), _model(model), state(ENone), maskRows(0), maskCols(0), maskRow(0), maskCol(0)
{

}

ConvolutionTask* ConvolutionFactory::createConvolutionTask(QString maskName, QObject *parent)
{
    ConvolutionMask* mask = getConvolutionMask( maskName);
    if (mask) {        
        return new ConvolutionTask(_model, *mask, parent);
    }
    return NULL;
}

ConvolutionMaskList &ConvolutionFactory::getConvolutionMasks()
{
    createConvolutionMasks();
    return masks;
}

ConvolutionMask* ConvolutionFactory::getConvolutionMask(const QString maskName)
{
    ConvolutionMaskList masks = getConvolutionMasks();
    for (int i = 0; i < masks.size(); i++) {
        ConvolutionMask* mask = masks[i];
        if (mask->name() == maskName) {
            return mask;
        }
    }
    return NULL;
}

bool ConvolutionFactory::createConvolutionMasks()
{
    if (!masks.isEmpty()) {
        qDebug() << "Masks already created";
        return true;
    }

    QFile file(":/resources/convolutionmasks.xml");
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Convulation masks file could not be opened!";
        return false;
    }

    QXmlSimpleReader xmlReader;
    QXmlInputSource source = QXmlInputSource(&file);
    QXmlDefaultHandler *handler = this;
    xmlReader.setContentHandler(handler);
    xmlReader.setErrorHandler(handler);

    if (!xmlReader.parse(source)) {
        return false;
    }

    for (int i = 0; i < masks.size(); ++i) {
        qDebug() << masks[i]->toString();
    }
    return true;
}

bool ConvolutionFactory::startElement(const QString &namespaceURI, const QString &localName,
                          const QString &qName, const QXmlAttributes &atts )
{
    qDebug() << "ConvolutionFactory::startElement:" << qName;
    if (qName == MASK) {
        qDebug() << "mask";
        state = EMask;
    }
    if (qName == NAME) {
        qDebug() << "name";
        maskName = "";
        maskRows = 0;
        maskCols = 0;
        maskRow = -1;
        maskCol = -1;
        state = EName;
    }
    else if (qName == ROWS) {
        qDebug() << "rows";
        state = ERows;
    }
    else if (qName == COLS) {
        qDebug() << "cols";
        state = ECols;
    }
    else if (qName == DATA) {
        qDebug() << "data";
        state = EData;
    }
    else if (qName == ROW) {
        qDebug() << "row";
        maskRow++;
        maskCol = -1;
        state = ERow;
    }
    else if (qName == COL) {
        qDebug() << "col";
        maskCol++;
        state = ECol;
    }
    return true;
}

bool ConvolutionFactory::endElement(const QString &namespaceURI, const QString &localName,
                        const QString &qName )
{
    qDebug() << "ConvolutionFactory::endElement:" << qName;
    state = ENone;
    return true;
}

bool ConvolutionFactory::characters (const QString &ch)
{
    if (state != ENone) {        
        qDebug() << "ConvolutionFactory::characters:" << ch;
    }
    switch(state) {
    case EName:
        maskName = ch;
        break;
    case ERows:
        maskRows = ch.toInt();
        break;
    case ECols:
        maskCols = ch.toInt();
        break;
    case EData:
        masks.append(new ConvolutionMask(maskName, maskRows, maskCols, this));
        break;
    case ECol:
        qDebug() << "Setting mask: [" << maskRow << ", " << maskCol << "],  " << ch.toDouble();
        masks.last()->setValue(maskRow, maskCol, ch.toDouble());
        break;
    default:
        break;
    }
    return true;
}

bool ConvolutionFactory::startDocument()
{
    qDebug() << "ConvolutionFactory::startDocument";
    state = ENone;
    return true;
}

bool ConvolutionFactory::endDocument()
{
    qDebug() << "ConvolutionFactory::endDocument";
    state = ENone;
    return true;
}

bool ConvolutionFactory::error(const QXmlParseException &exception)
{
    qDebug() << "ConvolutionFactory::error:" << exception.message();
    state = ENone;
    return false;
}
